##!"D:\xampp\perl\bin\perl.exe"

use strict;
use CGI;
use IO::Socket;
use Data::Dumper;
use Digest::MD5 qw(md5  md5_hex md5_base64);

use constant true               => 1;
use constant false              => 0;
use constant SERVER_VERSION	=> 0x00094100;
use constant PROTOCOL_VERSION	=> 0x00010D00;
use constant OPTIONS_NUM	=> 62;

print "Content-type: text/plain; charset=iso-8859-1\n\n";
print "<pre>";

my $gBoTerminated = false;
my $gCmd = "dump";
my $gTimeOut = 10;
my $gRunTime = time();
my $gAdminPwd = "";
my %gParams = ();

sub isTerminated{
    return $gBoTerminated;
}

sub Terminate{
    $gBoTerminated = true;
}

sub GetCmd{
    return $gCmd;
}

sub isTimeOut{
    return time()-$gRunTime > $gTimeOut;
}

sub ParserParams{
#=pod
    my $query = new CGI;
    $gBoTerminated = false;
    $gRunTime = time();

    $gCmd = $query->param('cmd');
    $gTimeOut = $query->param('timeout');
    $gParams{'user'} = $query->param('user');
    $gParams{'dir'}  = $query->param('dir');
    $gAdminPwd = $query->param('adminpwd');
#=cut
=pod
    $gCmd = "dump";
    $gTimeOut = 10;
    $gAdminPwd = "123456";
    %gParams = (
    'user' => 'peipei',
    'dir'  => 'd:'
    );
=cut
}

sub mypush{
    my $array = $_[0];
    push(@$array, $_[1]);
    #print Dumper($_[0]);
    #print Dumper($array);
}

sub MakeWord{
   $_[0] | $_[1] << 8;
}

sub MakeInt{
    my $wA = MakeWord($_[0], $_[1]);
    my $wB = MakeWord($_[2], $_[3]);
    return $wA | $wB << 16;
}

sub HiWord{
    return $_[0] >> 16;
}

sub LoWord{
    return $_[0] & 0x0000FFFF;
}

sub HiByte{
    return $_[0] >> 8;
}

sub LoByte{
    return $_[0] & 0xFF;
}

sub ParserString{
    my $data = \$_[0];
    my $strValue = \$_[1];    
    if(length($data) < 2){
	return false;
    }

    my $len = ord(substr($$data, 0, 1)) * 256 + ord(substr($$data, 1, 1));
    if(length($$data)-2 < $len){
	return false;
    }
    $$data = substr($$data, 2);
    $$strValue = substr($$data, 0, $len);
    $$data = substr($$data, $len);
    return true;
}

sub ParserInt{
    my $data = \$_[0];
    my $intValue = \$_[1];
    if(length($data) < 4){
	return false;
    }

    $$intValue = MakeInt(
	ord(substr($$data, 0, 1)),
	ord(substr($$data, 1, 1)),
	ord(substr($$data, 2, 1)),
	ord(substr($$data, 3, 1))
	);
    $$data = substr($$data, 4);
}

sub ParserWord{
    my $data = \$_[0];
    my $wordValue = \$_[1];
    if(length($$data) < 2){
	return false;
    }

    $$wordValue = ord(substr($$data, 0, 1))*256 + ord(substr($$data, 1, 1));
    $$data = substr($$data, 2);
}

sub ParserWord2{
    my $data = \$_[0];
    my $wordValue = \$_[1];
    if(length($$data) < 2){
	return false;
    }

    $$wordValue = ord(substr($$data, 0, 1))*256 + ord(substr($$data, 1, 1));
    $$data = substr($$data, 2);
}

sub ParserByte{
    my $data = \$_[0];
    my $byteValue = \$_[1];
    if(length($$data) < 1){
	return false;
    }
    
    $$byteValue = ord(substr($$data, 0, 1));
    $$data = substr($$data, 1);
}

sub count{
    my $array = $_[0];
    return @$array;
}

sub GetRequiredStringBuffrLen{
    return length($_[0]) + 2;
}

sub FillString{
    my $data = \$_[0];
    my $p    = \$_[1];
    my $str  = $_[2];

    if(length($str) == 0){
	@$$data[$$p++] = chr(0);
	@$$data[$$p++] = chr(0);
	return;
    }
    
    my $len = length($str);

    @$$data[$$p++] = chr($len >> 8);
    @$$data[$$p++] = chr($len &  0xFF);

    my $i = 0;
    for($i = 0; $i < $len; $i++){
	@$$data[$$p++] = (substr($str, $i, 1));
    }
}

sub FillInt{
    my $data = \$_[0];
    my $p    = \$_[1];
    my $nVal = $_[2];

    @$$data[$$p++] = chr($nVal >> 24);
    @$$data[$$p++] = chr($nVal >> 16);
    @$$data[$$p++] = chr($nVal >> 8);
    @$$data[$$p++] = chr($nVal &  0xFF0);
}

sub SpeedLimit_New{
    (
     'DataCheck' => false,
     'FromCheck' => false,
     'ToCheck'   => false,
     'Speed'     => 0,
     'Day'       => 0,
     'FromTimeH' => 0,
     'FromTimeM' => 0,
     'FromTimeS' => 0,
     'ToTimeH'   => 0,
     'ToTimeM'   => 0,
     'ToTimeS'   => 0,
     'DateY'     => 0,
     'DateM'     => 0,
     'DateD'     => 0
    );
}

sub SpeedLimit_GetRequiredBufferLen{
    return 4 + #Speed
	   4 + #date
	   6 + #2 * time
	   1;  #Weekday
}

sub SpeedLimit_FillBuffer{
    my @data = \$_[1];
    my $p    = \$_[2];

    $data[$$p++] = chr( $_[0]{'Speed'} >> 24);
    $data[$$p++] = chr(($_[0]{'Speed'} >> 16) % 256);
    $data[$$p++] = chr(($_[0]{'Speed'} >>  8) % 256);
    $data[$$p++] = chr( $_[0]{'Speed'} %  256);

    if($_[0]{'DateCheck'}){
	$data[$$p++] = $_[0]{'DateY'} >> 8;
	$data[$$p++] = $_[0]{'DateY'} %  256;
	$data[$$p++] = $_[0]{'DateM'};
	$data[$$p++] = $_[0]{'DateD'};
    }else{
	$data[$$p++] = chr(0);
	$data[$$p++] = chr(0);
	$data[$$p++] = chr(0);
	$data[$$p++] = chr(0);
    }

    if($_[0]{'FromCheck'}){
	$data[$$p++] = chr($_[0]{'FromTimeH'});
	$data[$$p++] = chr($_[0]{'FromTimeM'});
	$data[$$p++] = chr($_[0]{'FromTimeS'});
    }else{
	$data[$$p++] = chr(0);
	$data[$$p++] = chr(0);
	$data[$$p++] = chr(0);
    }
    
    if($_[0]{'ToCheck'}){
	$data[$$p++] = chr($_[0]{'ToTimeH'});
	$data[$$p++] = chr($_[0]{'ToTimeM'});
	$data[$$p++] = chr($_[0]{'ToTimeS'});
    }else{
	$data[$$p++] = chr(0);
	$data[$$p++] = chr(0);
	$data[$$p++] = chr(0);
    }
    
    $data[$$p++] = $_[0]{'Day'};
}

sub SpeedLimit_Init{
    my $data = \$_[1];
    if(length($$data) < 4+4+6+1){
	return false;
    }

    $_[0]{'Speed'} = ord(substr($$data, 0, 1)) << 24; $$data = substr($$data, 1);
    $_[0]{'Speed'} = ord(substr($$data, 0, 1)) << 16; $$data = substr($$data, 1);
    $_[0]{'Speed'} = ord(substr($$data, 0, 1)) <<  8; $$data = substr($$data, 1);
    $_[0]{'Speed'} = ord(substr($$data, 0, 1));       $$data = substr($$data, 1);
    if($_[0]{'Speed'} > 1048576){
	$_[0]{'Speed'} = 1048576;
    }

    if(ord(substr($$data, 0, 1)) == 0 && ord(substr($$data, 1, 1)) == 0 &&
       ord(substr($$data, 2, 1)) == 0 && ord(substr($$data, 3, 1)) == 0){
	$$data = substr($$data, 4);
	$_[0]{'DateCheck'} = false;
    }else{
	$_[0]{'DateCheck'} = true;
	$_[0]{'DateY'} = ord(substr($$data, 0, 1)) << 8; $$data = substr($$data, 1);
	$_[0]{'DateY'} |= ord(substr($$data, 0, 1));      $$data = substr($$data, 1);
	ParserByte($$data, $_[0]{'FromTimeM'});
	ParserByte($$data, $_[0]{'FromTimeD'});
	if($_[0]{'DateY'}<1900 || $_[0]{'DateY'}>3000 || $_[0]{'DateM'}<1 || $_[0]{'DateM'} || $_[0]{'DateD'}<1 || $_[0]{'DateD'}>31){
	    return false;
	}
    }

    if(ord(substr($$data, 0, 1)) == 0 && ord(substr($$data, 1, 1)) == 0 && ord(substr($$data, 2, 1)) == 0){
	$_[0]{'FromCheck'} = false;
	$$data = substr($$data, 3);
    }else{
	$_[0]{'FromCheck'} = true;
	ParserByte($$data, $_[0]{'FromTimeH'});
	ParserByte($$data, $_[0]{'FromTimeM'});
	ParserByte($$data, $_[0]{'FromTimeS'});
    }
    
    if(ord(substr($$data, 0, 1)) == 0 && ord(substr($$data, 1, 1)) == 0 && ord(substr($$data, 2, 1)) == 0){
	$_[0]{'ToCheck'} = false;
	$$data = substr($$data, 3);
    }else{
	$_[0]{'ToCheck'} = true;
	ParserByte($$data, $_[0]{'ToTimeH'});
	ParserByte($$data, $_[0]{'ToTimeM'});
	ParserByte($$data, $_[0]{'ToTimeS'});
    }
    
    ParserByte($$data, $_[0]{'Day'});
    return true;
}

sub Group_New{
    (
     'GroupName' => '',
     'IPLimit'   => 0,
     'UserLimit' => 0,
     'BypassUserLimit' => 0,
     'Enabled'   => false,
     'DisallowIPs' => [],
     'AllowedIPs'  => [],
     'Permissions' => [],
     'SpeedLimitType' => [0, 0],
     'SpeedLimit'  => [0, 0],
     'BypassServerSpeedLimit' => [0, 0],
     'SpeedLimits' => [[], []],
     'Comment'     => '',
     'ForceSsl'    => 0
    );
}

sub Group_GetRequiredBufferLen{
    my $len = 9;
    my $value = 0;
    my $value2 = 0;

    $len += GetRequiredStringBuffrLen($_[0]{'GroupName'});    
    
    $len += 4;
    foreach $value (@{$_[0]{'DisallowIPs'}}){
	$len += GetRequiredStringBuffrLen($value);
    }    
    foreach $value (@{$_[0]{'AllowedIPs'}}){
	$len += GetRequiredStringBuffrLen($value);
    }
    
    $len += 2;
    
    foreach $value (@{$_[0]{'Permissions'}}){
	$len += 2;

	my %obj = %$value;
	$len += GetRequiredStringBuffrLen($obj{'Dir'});

	$len += 2;
	foreach $value2 (@{$obj{'Aliases'}}){
	    $len += GetRequiredStringBuffrLen($value2);
	}

    }
    
    #Speed Limits
    $len += 6; #Basic Limits
    $len += 4; #Number of rules.
    my $i = 0;
    for($i = 0; $i < 2; $i++){
	foreach $value (@{$_[0]{'SpeedLimits'}[$i]}){
	    $len += SpeedLimit_GetRequiredBufferLen();
	}
    }

    $len += GetRequiredStringBuffrLen($_[0]{'Comment'});

    $len++; #Forcessl;
    
    return $len;
}

sub Group_FillBuffer{
    my $data = \$_[1];
    my $p    = \$_[2];

    FillString($$data, $$p, $_[0]{'GroupName'});
    FillInt($$data, $$p, $_[0]{'IPLimit'});
    FillInt($$data, $$p, $_[0]{'UserLimit'});

    my $options = ($_[0]{'BypassUserLimit'}) & 3;
    $options |= (($_[0]{'Enabled'} & 3)) << 2;    
    @$$data[$$p++] = chr($options & 0xFF);

    @$$data[$$p++] = chr(count($_[0]{'DisallowIPs'}) >> 8);
    @$$data[$$p++] = chr(count($_[0]{'DisallowIPs'}) &  0xFF);
    for my $value (@{$_[0]{'DisallowIPs'}}){
	FillString($$data, $$p, $value);
    }
    
    @$$data[$$p++] = chr(count($_[0]{'AllowedIPs'}) >> 8);
    @$$data[$$p++] = chr(count($_[0]{'AllowedIPs'}) &  0xFF);
    for my $value (@{$_[0]{'AllowedIPs'}}){
	FillString($$data, $$p, $value);
    }

    @$$data[$$p++] = chr(count($_[0]{'Permissions'}) >> 8);
    @$$data[$$p++] = chr(count($_[0]{'Permissions'}) &  0xFF);
    for my $value (@{$_[0]{'Permissions'}}){
	my %obj = %$value;
	FillString($$data, $$p, $obj{'Dir'});

	@$$data[$$p++] = chr(count($obj{'Aliases'}) >> 8);
	@$$data[$$p++] = chr(count($obj{'Aliases'}) &  0xFF);
	for my $value2 (@{$obj{'Aliases'}}){
	    FillString($$data, $$p, $value2);
	}

	my $rights = 0;
	$rights |= $obj{'boDirCreate'}    ? 0x0001:0;
	$rights |= $obj{'boDirDelete'}    ? 0x0002:0;
	$rights |= $obj{'boDirList'}      ? 0x0004:0;
	$rights |= $obj{'boDirSubDirs'}   ? 0x0008:0;
	$rights |= $obj{'boFileAppend'}   ? 0x0010:0;
	$rights |= $obj{'boFileDelete'}   ? 0x0020:0;
	$rights |= $obj{'boFileRead'}     ? 0x0040:0;
	$rights |= $obj{'boFileWrite'}    ? 0x0080:0;
	$rights |= $obj{'boIsHome'}       ? 0x0100:0;
	$rights |= $obj{'boAutoCreate'}   ? 0x0200:0;
	@$$data[$$p++] = chr($rights >> 8);
	@$$data[$$p++] = chr($rights &  0xFF);
    }#end if
   
    for(my $i = 0; $i < 2; $i++){
	@$$data[$$p++] = chr($_[0]{'SpeedLimitType'}[$i] & 3 + ($_[0]{'BypassServerSpeedLimit'}[$i] & 3) << 2);
	@$$data[$$p++] = chr($_[0]{'SpeedLimit'}[$i] >> 8);
	@$$data[$$p++] = chr($_[0]{'SpeedLimit'}[$i] &  0xFF);

	@$$data[$$p++] = chr(count($_[0]{'SpeedLimits'}[$i]) >> 8);
	@$$data[$$p++] = chr(count($_[0]{'SpeedLimits'}[$i]) &  0xFF);
	foreach my $value (@{$_[0]{'SpeedLimits'}[$i]}){
	    my %obj = %$value;
	    SpeedLimit_FillBuffer(\%obj, $$data, $p);
	}
    }
    FillString($$data, $$p, $_[0]{'Comment'});

    @$$data[$$p++] = chr($_[0]{'ForceSsl'});
}

sub Group_Init{
    my $data = \$_[1];
    if(!ParserString($$data, $_[0]{'GroupName'})){
	return false;
    }

    if(length($$data) < 11){
	return false;
    }

    ParserInt($$data, $_[0]{'IPLimit'});
    ParserInt($$data, $_[0]{'UserLimit'});
    my $nOptions = 0;
    my $NumDisallowedIPs = 0;
    my $Ip = '';
    ParserByte($$data, $nOptions);
    $_[0]{'BypassUserLimit'} = $nOptions & 0x03;
    $_[0]{'Enabled'}         = ($nOptions >> 2) & 0x03;
    ParserWord2($$data, $NumDisallowedIPs);
    while($NumDisallowedIPs--){
	if(!ParserString($$data, $Ip)){
	    return false;
	}
	mypush($_[0]{'DisallowIPs'}, $Ip);
    }

    if(length($$data) < 2){
	return false;
    }
    my $numAllowedIPs = 0;
    ParserWord2($$data, $numAllowedIPs);
    while($numAllowedIPs--){
	if(!ParserString($$data, $Ip)){
	    return false;
	}
	mypush($_[0]{'AllowedIPs'}, $Ip);
    }
    
    if(length($$data) < 2){
	return false;
    }
    my $dircount = 0;
    my $boGotHome = false;
    my $j = 0;
    my $i = 0;
    my $str = '';
    my $alias = '';
    my $aliascount = 0;
    ParserWord2($$data, $dircount);
    for($j = 0; $j < $dircount; $j++){
	my %dirObj = ();
	$dirObj{'Aliases'} = [];
	$dirObj{'Dir'}     = '';
	if(!ParserString($$data, $str)){
	    return false;
	}
	$dirObj{'Dir'}     = $str;

	ParserWord2($$data, $aliascount);
	for($i = 0; $i < $aliascount; $i++){
	    if(!ParserString($$data, $alias)){
		return false;
	    }
	    mypush($dirObj{'Aliases'}, $alias);
	}

	if(length($$data) < 2){
	    return false;
	}
	
	my $rights = 0;
	ParserWord2($$data, $rights);
	$dirObj{'boDirCreate'}    = $rights & 0x0001 ? 1:0;
	$dirObj{'boDirDelete'}    = $rights & 0x0002 ? 1:0;
	$dirObj{'boDirList'}      = $rights & 0x0004 ? 1:0;
	$dirObj{'boDirSubDirs'}   = $rights & 0x0008 ? 1:0;
	$dirObj{'boFileAppend'}   = $rights & 0x0010 ? 1:0;
	$dirObj{'boFileDelete'}   = $rights & 0x0020 ? 1:0;
	$dirObj{'boFileRead'}     = $rights & 0x0040 ? 1:0;
	$dirObj{'boFileWrite'}    = $rights & 0x0080 ? 1:0;
	$dirObj{'boIsHome'}       = $rights & 0x0100 ? 1:0;
	$dirObj{'boAutoCreate'}   = $rights & 0x0200 ? 1:0;

	if($dirObj{'boIsHome'}){
	    if(!$boGotHome){
		$boGotHome = true;
	    }else{
		$dirObj{'boIsHome'} = false;
	    }
	}
	mypush($_[0]{'Permissions'}, \%dirObj);
    }#end for
    
    for($i = 0; $i < 2; $i++){
	if(length($$data) < 5){
	    return false;
	}
	
	$_[0]{'SpeedLimitType'}[$i] = ord(substr($$data, 0, 1)) & 3;
	$_[0]{'BypassServerSpeedLimit'}[$i] = (ord(substr($$data, 0, 1)) >> 2) & 3; $$data = substr($$data, 1);
	$_[0]{'SpeedLimit'}[$i] = ord(substr($$data, 0, 1)) << 8; $$data = substr($$data, 1);
	$_[0]{'SpeedLimit'}[$i] = ord(substr($$data, 0, 1)); $$data = substr($$data, 1);

	if(!$_[0]{'SpeedLimit'}[$i]){
	    $_[0]{'SpeedLimit'}[$i] = 10;
	}
	
	my $num = 0;
	ParserWord2($$data, $num);
	while($num--){
	    my $speedLimitObj = SpeedLimit_New();
	    if(SpeedLimit_Init($speedLimitObj, $$data)){
		mypush($_[0]{'SpeedLimits'}[$i], $speedLimitObj);
	    }else{
		return false;
	    }
	    if(length($$data) <= 0){
		return false;
	    }
	}
    }#end for 
    if(!ParserString($$data, $_[0]{'Comment'})){
	return false;
    }

    if(length($$data) > 0){
	ParserByte($$data, $_[0]{'ForceSsl'});
    }
    
    print "init\n";
    return true;
}

sub Group_CreateNew{
    (
     'GroupName' => '',
     'IPLimit'   => 0,
     'UserLimit' => 0,
     'BypassUserLimit' => 0,
     'Enabled'   => true,
     'DisallowIPs' => [],
     'AllowedIPs'  => [],
     'SpeedLimitType' => [0, 0],
     'SpeedLimit'  => [0, 0],
     'BypassServerSpeedLimit' => [0, 0],
     'SpeedLimits' => [[], []],
     'Comment'     => '',
     'ForceSsl'    => 0,
     'Permissions' => [
	 {
	  'Aliases'   => [],
	  'Dir'       => $_[0],
	  'boDirCreate'    => 1,
	  'boDirDelete'    => 1,
	  'boDirList'      => 1,
	  'boDirSubDirs'   => 1,
	  'boFileAppend'   => 1,
	  'boFileDelete'   => 1,
	  'boFileRead'     => 1,
	  'boFileWrite'    => 1,
	  'boIsHome'       => 1,
	  'boAutoCreate'   => 0
	 }
	 ]
    );
}

sub User_New{
    my %self = Group_New();
}

sub User_GetRequiredBufferLen{
    my $len = Group_GetRequiredBufferLen($_[0]);
    $len += GetRequiredStringBuffrLen($_[0]{'UserName'});
    $len += GetRequiredStringBuffrLen($_[0]{'Password'});
    return $len;
}

sub User_FillBuffer{
    my $data = \$_[1];
    my $p    = \$_[2];
    Group_FillBuffer($_[0], $$data, $$p);
    
    FillString($$data, $$p, $_[0]{'UserName'});
    FillString($$data, $$p, $_[0]{'Password'});
    #print Dumper($data);
}

sub User_Init{
    my $data = \$_[1];
    if(!Group_Init($_[0], $$data)){
	return false;
    }

    ParserString($$data, $_[0]{'UserName'});
    ParserString($$data, $_[0]{'Password'});
    return true;
}

sub User_CreateNew{
    my %obj = Group_CreateNew($_[1]);
    $obj{'UserName'} = $_[0];
    $obj{'Password'} = '';
    return %obj;
}

sub UserAdmin_New{
    my %obj = (
     'GroupList' => [],
     'UserList'  => []
    );
    #return $obj;
}

sub UserAdmin_Init{
    my $data = \$_[1];

    if(length($data) < 2){
	return false;
    }
    my $i = 0;
    my $num = 0;
    ParserWord($$data, $num);
    print "useradmin.init groupnum=$num\n";
    for($i = 0; $i < $num; $i++){
	my %groupObj = Group_New();
	if(!Group_Init(\%groupObj, $$data)){
	    print "Group init error!\n";
	    return false;
	}
	mypush($_[0]{'GroupList'}, \%groupObj);
	print "group$i name=" . $groupObj{'GroupName'} . "\n";
	if(length($$data) <= 0){
	    last;
	}
    }

    if(length($$data) < 2){
	return false;
    }
    ParserWord($$data, $num);
    print "useradmin.init usernum=$num\n";
    for($i = 0; $i < $num; $i++){
	my %userObj = User_New();
	if(!User_Init(\%userObj, $$data)){
	    print "User init error!\n";
	    return false;
	}
	mypush($_[0]{'UserList'}, \%userObj);
	print "user$i name=" . $userObj{"UserName"} . "\n";
	if(length($$data) <= 0){
	    last;
	}
    }

    print "useradmin.init\n";
    print Dumper($_[0]{'UserList'});
    if(GetCmd() eq 'dump'){
	Terminate();
    }
    return true;
}

sub UserAdmin_FillBuffer{
    my $groupObj = undef;
    my $userObj  = undef;
    my $len      = 0;
    my $p        = 0;
    my @data     = ();
    my $i        = 0;
    my %obj      = ();
    my %obj2     = ();
    
    $len = 4;

    foreach $groupObj (@{$_[0]{'GroupList'}}){
	$len += Group_GetRequiredBufferLen($groupObj);
    }
    foreach $userObj (@{$_[0]{'UserList'}}){
	$len += User_GetRequiredBufferLen($userObj);
    }

    for($i = 0; $i < $len; $i++){
	mypush(\@data, chr(0));
    }

    $p = 0;
    $data[$p++] = chr(count($_[0]{'GroupList'}) / 256);
    $data[$p++] = chr(count($_[0]{'GroupList'}) % 256);
    foreach $groupObj (@{$_[0]{'GroupList'}}){
	Group_FillBuffer($groupObj, \@data, $p);
    }

    if(GetCmd() eq 'chgdir'){
	my $boFound = false;
	my $boFoundUser = false;
	my $dirObj = undef;
	foreach $userObj (@{$_[0]{'UserList'}}){
	    %obj = %$userObj;
	    if($obj{'UserName'} eq $gParams{'user'}){
		$boFoundUser = true;
		foreach $dirObj (@{$obj{'Permissions'}}){
		    %obj2 = %$dirObj;
		    if($obj2{'Dir'} eq $gParams{'dir'}){
			$boFound = true;
			last;
		    }
		}
		#print "!" . $boFound . '-' . count($obj{'Permissions'}) . "\n";
		if($boFound && (count($obj{'Permissions'}))>0){
		    $obj{'Permissions'}[0]{'Dir'} = $gParams{'dir'};
		    print Dumper($_[0]) . "\n";
		}else{
		    print "not found user=" . $gParams{'user'} . " dir=" . $gParams{'dir'} . "\n";
		}
	    }
	}#end for
	if(!$boFoundUser){
	    my %newUser = User_CreateNew($gParams{'user'}, $gParams{'dir'});
	    mypush($_[0]{'UserList'}, \%newUser);
	    print $gParams{'user'} . " not found created the user.\n";
	}
    }


    $data[$p++] = chr(count($_[0]{'UserList'}) / 256);
    $data[$p++] = chr(count($_[0]{'UserList'}) % 256);
    foreach $userObj (@{$_[0]{'UserList'}}){
	%obj = %$userObj;
	User_FillBuffer(\%obj, \@data, $p);
    }

    print "-------------------------------------------------------------------\n";
    print Dumper($_[0]);
    my $settingData = \$_[1];
    $$settingData = '';
    for($i = 0; $i < @data; $i++){
#	printf("[$i]=%x\n", ord($data[$i]));
	$$settingData .= ($data[$i]);
    }
#    print $$settingData . "\n";
}

sub FZSClient_New{
   (
   'Socket' => 0,
   'LastCheckTime' => time(),
   'ConnectionState' => 1,
   'RecvBuffer' => '',
   'Connection' => 0,
   
   'RemoteIP' => 'localhost',#'127.0.0.1',
   'RemotePort' => 14147,
   'SocketType' => 2
   );
}

sub FZSClient_Init{
    print localtime() . " FZSClient_Init begin\n";
    if($_[0]{'SocketType'} == 1){
	socket(SOCK, PF_INET, SOCK_STREAM, 6) or die "Can't createsocket:$!";
	my $dest = sockaddr_in($_[0]{'RemotePort'}, inet_aton($_[0]{'RemoteIP'}));
	connect(SOCK, $dest) or die "Can't connect:$!";
    }else{
	eval {
	$_[0]{'Socket'} = IO::Socket::INET->new(
#	    Blocking => 0,
	    PeerAddr => $_[0]{'RemoteIP'},
	    PeerPort => $_[0]{'RemotePort'},
	    Proto    => "tcp",
	    Type     => SOCK_STREAM,
	    Timeout  => 3
	    ) or die "Can't connect to $_[0]{'RemoteIP'}:$_[0]{'RemotePort'}:$!\n";
	};
	if($@){
	    my $e = $@;
	    print $e;
	}
	
    }
    print localtime() . " FZSClient_Init end\n";
}

sub FZSClient_Run{
    print localtime() . " FZSClient_Run\n";
    while(!isTimeOut() && !isTerminated()){
	if($_[0]{'SocketType'} == 1){
	}else{
	    my $tmpBuf = '';
	    my $len = 10;
	    my $retVal = $_[0]{'Socket'}->recv($tmpBuf, 1024, 0);
	    if($retVal){
		if(length($tmpBuf) > 0){
		    $_[0]{'RecvBuffer'} = $_[0]{'RecvBuffer'} . $tmpBuf;
		    while(FZSClient_ParserRecvBuffer($_[0])){
		    }
		}
	    }
	    if(!defined($_[0]{'Socket'}->connected())){
		print "socket disconnect...\n";
		return;
	    }
	}
    }
}

sub FZSClient_ParserRecvBuffer{
    my $recvBuffer = $_[0]{'RecvBuffer'};
    if($_[0]{'ConnectionState'} == 1){#ConnectionState = 1
	if(length($recvBuffer) < 5){
	    return false;
	}	
	if(substr($recvBuffer, 0, 1) ne 'F' ||
	   substr($recvBuffer, 1, 1) ne 'Z' ||
	   substr($recvBuffer, 2, 1) ne 'S'){
	    print "Protocol error:Unknow protocol head\n";
	    return false;
	}
	my $len = ord(substr($recvBuffer, 3, 1)) * 256 +
	    ord(substr($recvBuffer, 4, 1));
	if($len != 4){
	    print "Protocol error: Invalid server version length:$len\n";
	    return false;
	}
	if(length($recvBuffer) < 9){
	    return false;
	}
	my $version = MakeInt(
	    ord(substr($recvBuffer, 5, 1)),
	    ord(substr($recvBuffer, 6, 1)),
	    ord(substr($recvBuffer, 7, 1)),
	    ord(substr($recvBuffer, 8, 1))
	    );
	if($version != SERVER_VERSION){
	   print "Protocol warning: Server version mismatch: Server version\n";
	}
	if(length($recvBuffer) < 11){
	    return false;
	}
	$len = ord(substr($recvBuffer, 9, 1)) * 256 +
	    ord(substr($recvBuffer, 10, 1));
	if($len != 4){
	    print "Protocol error: Invalid protocol version\n";
	    return false;
	}
	if(length($recvBuffer) < 15){
	    return false;
	}
	$version = MakeInt(
	    ord(substr($recvBuffer, 11, 1)),
	    ord(substr($recvBuffer, 12, 1)),
	    ord(substr($recvBuffer, 13, 1)),
	    ord(substr($recvBuffer, 14, 1))
	    );
	if($version != PROTOCOL_VERSION){
	    print "Protocol warning: Protocol version mismatch\n";
	}
	$_[0]{'RecvBuffer'} = substr($recvBuffer, 15);
	$_[0]{'ConnectionState'} = 2;
	print "ConnectionState = 2\n";	
	print "length(recvBuffer)=" . length($_[0]{'RecvBuffer'}) . "\n";
    }elsif($_[0]{'ConnectionState'} == 2){#ConnectionState = 2
	if(length($recvBuffer) < 5){
	    return false;
	}
	if((ord(substr($recvBuffer, 0, 1)) & 0x03) > 2){
	    print "Protocol error: Unknown command type\n";
	    return false;
	}
	my $len = MakeInt(
	    ord(substr($recvBuffer, 1, 1)),
	    ord(substr($recvBuffer, 2, 1)),
	    ord(substr($recvBuffer, 3, 1)),
	    ord(substr($recvBuffer, 4, 1))
	    );
	#print "len=$len length(recvBuffer)=" . length($recvBuffer) . "\n";
	if($len + 5 <= length($recvBuffer)){
	    if((ord(substr($recvBuffer, 0, 1))&0x03) == 0 &&
	       (ord(substr($recvBuffer, 0, 1))&0x7C)>>2 == 0) {
		    if($len < 4){
			print "Invalid auth data\r\n";
			return false;
		    }
		    my $noncelen1 = ord(substr($recvBuffer, 5, 1)) * 256 +
			ord(substr($recvBuffer, 6, 1));
		    if(($noncelen1+2) > ($len-2)){
			print "Invalid auth data2\n";
			return false;
		    }
		    my $noncelen2 = ord(substr($recvBuffer, 5+2+$noncelen1, 1))*256 + ord(substr($recvBuffer, 5+2+$noncelen1+1, 1));
		    if(($noncelen1 + $noncelen2 + 4) > $len){
			print "Invalid auth data3\n";
			return false;
		    }
		    print "noncelen1=$noncelen1 noncelen2=$noncelen2\n";
		    my $authData = substr($recvBuffer, 5+2, $noncelen1) .
			$gAdminPwd . 
			substr($recvBuffer, 5+4+$noncelen1, $noncelen2);
		    $_[0]{'RecvBuffer'} = substr($recvBuffer, $len + 5);
		    FZSClient_SendCommand($_[0], 0, md5($authData));
		    $_[0]{'ConnectionState'} = 3;
		    print "ConnectionState = 3\n";
		    return true;		    
	    }elsif((ord(substr($recvBuffer, 0, 1))&0x03) == 1 &&
		   (ord(substr($recvBuffer, 0, 1))&0x7C) == 0){
		$_[0]{'ConnectionState'} = 3;
		print "ConnectionState2 = 3\n";
		FZSClient_ParserReply($_[0], (ord(substr($recvBuffer, 0, 1))&0x7C) >> 2, substr($recvBuffer, 5));
	    }else{
		print "Protocol error: Unknown command\n";
		return false;
	    }#endif
	    $_[0]{'RecvBuffer'} = substr($recvBuffer, $len + 5);
	}#endif
    }elsif($_[0]{'ConnectionState'} == 3){#ConnectionState = 3
	if(length($recvBuffer) < 5){
	    return false;
	}
	my $nType = ord(substr($recvBuffer, 0, 1)) & 0x03;
	my $nID   = (ord(substr($recvBuffer,0, 1)) & 0x7C) >> 2;
	#print "nType=$nType nID=$nID\n";
	if($nType > 2 || $nType < 1){
	    print "Protocol error: Unknown command type($nType), closing connection3\n";
	    return false;
	}else{
	    my $len = MakeInt(
		ord(substr($recvBuffer, 1, 1)),
		ord(substr($recvBuffer, 2, 1)),
		ord(substr($recvBuffer, 3, 1)),
		ord(substr($recvBuffer, 4, 1))
		);
	    if($len > 0xFFFFFF){
		print "Protocol error: Invalid data length ($len) for command($nType:$nID)\n";
		return false;
	    }elsif(length($recvBuffer) < $len+5){
		return false;
	    }else{
		if($nType == 1){
		    FZSClient_ParserReply($_[0], $nID, substr($recvBuffer, 5));
		}elsif($nType == 2){
		    FZSClient_ParserStatus($nID);
		}else{
		    print "Protocol warning: Command Type $nID not implemented\n";
		}
	    }
	    $_[0]{'RecvBuffer'} = substr($recvBuffer, $len+5);
	}
    }
    return true;
}

sub FZSClient_ParserStatus{
    print "ParserStatus\n";
}

sub FZSClient_ParserReply{
    my $nReplyID = $_[1];
    my $data     = $_[2];
    if($nReplyID == 0){
	print "Logged on\n";
	FZSClient_SendCommand($_[0], 2, "");
	FZSClient_SendCommand($_[0], 3, "\0");
	FZSClient_SendCommand($_[0], 6, "");
	print "Retrieving account settings, please wait....\n";
    }elsif($nReplyID == 2){
    }elsif($nReplyID == 3){
    }elsif($nReplyID == 5){
    }elsif($nReplyID == 6){
	if(length($data) == 1){
	    if(ord(substr($data, 0, 1)) == 0){
		print "Done Sending account settings.\n";
	    }elsif(ord(substr($data, 0, 1)) == 1){
		print "Could not change account settings.\n";	       
	    }
	    return false;
	}
	print "Done retrieving account settings.\n";
	if(length($data) < 2){
	    print "Protocol error: unexcepted data length.\n";
	}else{
	    my %userAdmin = UserAdmin_New();
	    if(UserAdmin_Init(\%userAdmin, $data)){
		if(GetCmd() eq "chgdir"){
		    my $setingData = '';
		    UserAdmin_FillBuffer(\%userAdmin, $setingData);
		    FZSClient_SendCommand($_[0], 6, $setingData);
		}
	    }
	}
    }else{
	print "not ParserReply\n";
    }
}

sub FZSClient_SendCommand{
    my $Type = $_[1];
    my $Data = $_[2];
    my $DataLen = length($Data);
    my $Package = chr($Type << 2) . 
	chr(LoByte(LoWord($DataLen))) .
	chr(HiByte(LoWord($DataLen))) .
	chr(LoByte(HiWord($DataLen))) .
	chr(HiByte(HiWord($DataLen))) .
	$Data;     
    $_[0]{'Socket'}->send($Package);
}

ParserParams();
#exit;

my %fzsClient = FZSClient_New();
FZSClient_Init(\%fzsClient);
FZSClient_Run(\%fzsClient);
print "---------------------------------------------------------------\n";
print "</pre>";

